Skip to content

Add test isolation utilities for async testing with EnforcerServer#58

Closed
Copilot wants to merge 5 commits intomasterfrom
copilot/fix-shared-enforcer-state
Closed

Add test isolation utilities for async testing with EnforcerServer#58
Copilot wants to merge 5 commits intomasterfrom
copilot/fix-shared-enforcer-state

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 1, 2026

EnforcerServer uses a global ETS table (:enforcers_table) keyed by enforcer name. Tests sharing the same enforcer name experience race conditions when run with async: true - policies added in one test get deleted by another's cleanup, causing intermittent failures.

Changes

Test utilities module (Casbin.TestHelper)

  • unique_enforcer_name/1 - Generate unique enforcer names per test using process refs + timestamp + random
  • start_test_enforcer/2 - Start isolated enforcer under supervisor
  • cleanup_test_enforcer/1 - Stop process and remove from ETS table
  • reset_test_enforcer/2 - Clear policies without stopping

Minimal inline documentation focused on core functionality only.

Usage

defmodule MyApp.AclTest do
  use ExUnit.Case, async: true
  import Casbin.TestHelper
  
  setup do
    name = unique_enforcer_name()
    {:ok, _} = start_test_enforcer(name, "model.conf")
    on_exit(fn -> cleanup_test_enforcer(name) end)
    {:ok, enforcer_name: name}
  end
  
  test "isolated test", %{enforcer_name: name} do
    EnforcerServer.add_policy(name, {:p, ["alice", "data", "read"]})
    assert EnforcerServer.allow?(name, ["alice", "data", "read"])
  end
end

Backward compatible - existing tests with shared enforcers continue working.

Original prompt

This section details on the original issue you should resolve

<issue_title>Shared Global Enforcer state breaks Async tests</issue_title>
<issue_description>## Problem
When using EnforcerServer with a named enforcer (e.g., "reach_enforcer"), all tests share the same global state, making async: true tests fail with race conditions.

What Happened

# This fails with async: true
defmodule Reach.Casbin.AclTest do
  use Reach.CasbinCase, async: true  # ❌ Tests interfere with each other
  
  test "admin has permissions" do
    create_test_policies(test_org_id)  # Adds policies
    # Another test's cleanup deletes these policies mid-test!
    assert Acl.allow?(...) # Returns false unexpectedly
  end
end

Symptoms

  • Policies.list() returns [] even after adding policies
  • add_policy returns {:error, :already_existed} but policies aren't in memory
  • Tests pass individually but fail when run together

Root Cause

# All tests use the same enforcer instance
@enforcer_name "reach_enforcer"
EnforcerServer.add_policy(@enforcer_name, ...)

One test's on_exit cleanup deletes policies while another test is running.

Workaround

# Must disable async
defmodule Reach.Casbin.AclTest do
  use Reach.CasbinCase  # Removed: async: true
end

Proposed Solutions

  1. Support dynamic enforcer names per test
  2. Provide enforcer isolation/sandboxing for tests
  3. Document the async limitation</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@hsluoyz hsluoyz marked this pull request as ready for review January 1, 2026 13:31
Copilot AI and others added 3 commits January 1, 2026 13:36
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix shared global enforcer state in Async tests Add test isolation utilities for async testing with EnforcerServer Jan 1, 2026
Copilot AI requested a review from hsluoyz January 1, 2026 13:41
@hsluoyz
Copy link
Copy Markdown
Member

hsluoyz commented Jan 1, 2026

@copilot don't add any markdown docs. don't add test files. focus on core code logic change

Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 1, 2026

@copilot don't add any markdown docs. don't add test files. focus on core code logic change

Removed all markdown documentation and test files. PR now contains only core Casbin.TestHelper module with minimal inline docs (62 lines). Commit: 7ec0268

@hsluoyz hsluoyz closed this Jan 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shared Global Enforcer state breaks Async tests

3 participants